// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
#include <pollux/functions/registerer.h>
#include <pollux/functions/prestosql/comparisons.h>
#include <pollux/functions/prestosql/types/ip_address_registration.h>
#include <pollux/functions/prestosql/types/ip_address_type.h>
#include <pollux/functions/prestosql/types/ip_prefix_registration.h>
#include <pollux/functions/prestosql/types/ip_prefix_type.h>
#include <pollux/functions/prestosql/types/timestamp_with_time_zone_registration.h>
#include <pollux/functions/prestosql/types/timestamp_with_time_zone_type.h>

namespace kumo::pollux::functions {
    namespace {
        template<template <class> class T, typename TReturn>
        void registerNonSimdizableScalar(const std::vector<std::string> &aliases) {
            register_function<T, TReturn, Varchar, Varchar>(aliases);
            register_function<T, TReturn, Varbinary, Varbinary>(aliases);
            register_function<T, TReturn, bool, bool>(aliases);
            register_function<T, TReturn, Timestamp, Timestamp>(aliases);
            register_function<T, TReturn, TimestampWithTimezone, TimestampWithTimezone>(
                aliases);
            register_function<T, TReturn, IPAddress, IPAddress>(aliases);
        }
    } // namespace

    void registerComparisonFunctions(const std::string &prefix) {
        // Comparison functions also need TimestampWithTimezoneType,
        // independent of DateTimeFunctions
        registerTimestampWithTimeZoneType();
        registerIPAddressType();
        registerIPPrefixType();

        registerNonSimdizableScalar<EqFunction, bool>({prefix + "eq"});
        POLLUX_REGISTER_VECTOR_FUNCTION(udf_simd_comparison_eq, prefix + "eq");
        register_function<EqFunction, bool, Generic<T1>, Generic<T1> >({prefix + "eq"});

        registerNonSimdizableScalar<NeqFunction, bool>({prefix + "neq"});
        POLLUX_REGISTER_VECTOR_FUNCTION(udf_simd_comparison_neq, prefix + "neq");
        register_function<NeqFunction, bool, Generic<T1>, Generic<T1> >(
            {prefix + "neq"});

        registerNonSimdizableScalar<LtFunction, bool>({prefix + "lt"});
        POLLUX_REGISTER_VECTOR_FUNCTION(udf_simd_comparison_lt, prefix + "lt");
        register_function<LtFunction, bool, Orderable<T1>, Orderable<T1> >(
            {prefix + "lt"});

        registerNonSimdizableScalar<GtFunction, bool>({prefix + "gt"});
        POLLUX_REGISTER_VECTOR_FUNCTION(udf_simd_comparison_gt, prefix + "gt");
        register_function<GtFunction, bool, Orderable<T1>, Orderable<T1> >(
            {prefix + "gt"});

        registerNonSimdizableScalar<LteFunction, bool>({prefix + "lte"});
        POLLUX_REGISTER_VECTOR_FUNCTION(udf_simd_comparison_lte, prefix + "lte");
        register_function<LteFunction, bool, Orderable<T1>, Orderable<T1> >(
            {prefix + "lte"});

        registerNonSimdizableScalar<GteFunction, bool>({prefix + "gte"});
        POLLUX_REGISTER_VECTOR_FUNCTION(udf_simd_comparison_gte, prefix + "gte");
        register_function<GteFunction, bool, Orderable<T1>, Orderable<T1> >(
            {prefix + "gte"});

        register_function<DistinctFromFunction, bool, Generic<T1>, Generic<T1> >(
            {prefix + "distinct_from"});

        register_function<BetweenFunction, bool, int8_t, int8_t, int8_t>(
            {prefix + "between"});
        register_function<BetweenFunction, bool, int16_t, int16_t, int16_t>(
            {prefix + "between"});
        register_function<BetweenFunction, bool, int32_t, int32_t, int32_t>(
            {prefix + "between"});
        register_function<BetweenFunction, bool, int64_t, int64_t, int64_t>(
            {prefix + "between"});
        register_function<BetweenFunction, bool, double, double, double>(
            {prefix + "between"});
        register_function<BetweenFunction, bool, float, float, float>(
            {prefix + "between"});
        register_function<BetweenFunction, bool, Varchar, Varchar, Varchar>(
            {prefix + "between"});
        register_function<BetweenFunction, bool, Date, Date, Date>(
            {prefix + "between"});
        register_function<BetweenFunction, bool, Timestamp, Timestamp, Timestamp>(
            {prefix + "between"});
        register_function<
            BetweenFunction,
            bool,
            LongDecimal<P1, S1>,
            LongDecimal<P1, S1>,
            LongDecimal<P1, S1> >({prefix + "between"});
        register_function<
            BetweenFunction,
            bool,
            ShortDecimal<P1, S1>,
            ShortDecimal<P1, S1>,
            ShortDecimal<P1, S1> >({prefix + "between"});
        register_function<
            BetweenFunction,
            bool,
            IntervalDayTime,
            IntervalDayTime,
            IntervalDayTime>({prefix + "between"});
        register_function<
            BetweenFunction,
            bool,
            IntervalYearMonth,
            IntervalYearMonth,
            IntervalYearMonth>({prefix + "between"});
        register_function<
            BetweenFunction,
            bool,
            TimestampWithTimezone,
            TimestampWithTimezone,
            TimestampWithTimezone>({prefix + "between"});
        register_function<BetweenFunction, bool, IPAddress, IPAddress, IPAddress>(
            {prefix + "between"});
        register_function<BetweenFunction, bool, IPPrefix, IPPrefix, IPPrefix>(
            {prefix + "between"});
    }
} // namespace kumo::pollux::functions
